/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * ClientUI.java
 *
 * Created on Apr 25, 2011, 10:57:21 PM
 */
package fss.client;

import fss.client.ui.ClientDisplayState;
import fss.client.ui.CustomList;
import fss.client.ui.FileListItem;
import fss.client.ui.LoginUI;
import fss.client.ui.TransferProgressDialog;
import fss.common.LookupServiceRegistry;
import fss.common.communication.DownloadRequest;
import fss.common.communication.QueryResult;
import fss.common.communication.UploadRequest;
import fss.remote.ServiceRegistry;
import fss.remote.util.RemoteFileService;
import fss.remote.util.RemoteFileServiceRegistry;
import fss.transfer.Transfer;
import fss.transfer.TransferId;
import fss.transfer.TransferSource;
import fss.transfer.TransferType;
import fss.transfer.TransferUtils;
import fss.util.FssUtils;
import fss.util.rmi.RmiId;
import fss.util.rmi.RmiUtils;
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import sun.awt.DisplayChangedListener;

/**
 *
 * @author hieu
 */
public class ClientUI
  extends javax.swing.JFrame
  implements FileServiceClientUI, Observer
{

  private enum MenuListType
  {
    eRegistry,
    eService,
    eIncompleteFiles
  }
  /** Class variables */
  DefaultListModel mMenuItemModel = new DefaultListModel();
  DefaultListModel mClientFilesModel = new DefaultListModel();
  DefaultListModel mServerFilesModel = new DefaultListModel();
  private ClientUIModel mClientModel;
  private ServiceRegistry mRegistry;
  private RemoteFileService mServer;
  private Registry mRmiRegistry;
  private RmiId mClientId;
  private RmiId mServerId;
  private ClientDisplayState mCurrentState = ClientDisplayState.eIdle;
  private CustomList mMenuList;
  private MenuListType mMenuListType;
  private TransferProgressDialog mTransferProgress = new TransferProgressDialog();

  /** Creates new form ClientUI */
  public ClientUI()
  {
    initComponents();
    setLocationRelativeTo(null);
    mMenuList = new CustomList(mMenuItemModel);
    mMenuListPanel.add(mMenuList, BorderLayout.CENTER);
    setupFileListEvents();
    getClientInfo();
    lookupRegistry();
    updateState(mCurrentState);
  }

  /**
   * Pops up the log in and obtain the client rmi
   */
  private void getClientInfo()
  {
    boolean tSuccess = false;

    /**
     * Reappear the dialog to obtain client info
     */
    while (!tSuccess)
    {
      LoginUI mLogin = new LoginUI();
      mLogin.setVisible(true);
      RmiId tClientId = mLogin.getRmiId();
      mLogin.dispose();
      setTitle("Hello " + tClientId.getName());

      mClientModel = new ClientUIModel(this, tClientId);
      mClientModel.addObserver(this);
      try
      {
        mRmiRegistry = RmiUtils.exportFssClient(mClientModel);
        mClientId = tClientId;
      }
      catch (RemoteException aEx)
      {
        JOptionPane.showMessageDialog(
          this, "An error occur while trying to connect to RMI Registry. "
          + "Please try again.");
      }

      updateClientFileList();
      tSuccess = true;
    }
  }

  /**
   * Look up the registry and obtain the first stub it find
   */
  private void lookupRegistry()
  {
    boolean tSuccess = false;
    while (!tSuccess)
    {
      ArrayList<RmiId> tAvailableRegistries =
        LookupServiceRegistry.getAvailableRegistryList();
      for (RmiId tTest : tAvailableRegistries)
      {
        try
        {
          ServiceRegistry tRegistry = (ServiceRegistry) RmiUtils.getRemoteObject(tTest);
          tRegistry.getId();

          /**
           * If no RemoteException, then assume successful
           */
          mRegistry = tRegistry;
          tSuccess = true;
          break;
        }
        catch (RemoteException aEx)
        {
          aEx.printStackTrace();
        }
      }

      /**
       * If no registry found. Try again every 1 sec
       */
      try
      {
        Thread.sleep(1000);
      }
      catch (Exception aEx)
      {
      }
    }
  }

  private void setupFileListEvents()
  {
    mClientFileList.addMouseListener(new MouseAdapter()
    {

      @Override
      public void mouseClicked(MouseEvent aEvent)
      {
        super.mouseClicked(aEvent);
        int tIdx = mClientFileList.locationToIndex(aEvent.getPoint());
        if (tIdx == -1)
        {
          mUpload.setEnabled(false);
        }
        else
        {
          mUpload.setEnabled(true);
        }
      }
    });

    mServerFileList.addMouseListener(new MouseAdapter()
    {

      @Override
      public void mouseClicked(MouseEvent aEvent)
      {
        super.mouseClicked(aEvent);
        int tIdx = mServerFileList.locationToIndex(aEvent.getPoint());
        if (tIdx == -1)
        {
          mDownload.setEnabled(false);
        }
        else
        {
          mDownload.setEnabled(true);
        }
      }
    });
  }

  /**
   * Query a file name and display the remote services that has the queried file
   * @param aFileName
   */
  private void displayQueryResult(String aFileName)
  {
    try
    {
      RemoteFileServiceRegistry tFileServiceRegistry =
        (RemoteFileServiceRegistry) mRegistry;
      List<QueryResult> tResults = tFileServiceRegistry.query(aFileName);
      ArrayList<RmiId> tResultIds = new ArrayList<RmiId>();
      for (QueryResult tResult : tResults)
      {
        tResultIds.add(tResult.getId());
      }
      setUpMenuList(tResultIds, MenuListType.eService);
      updateState(ClientDisplayState.eQueryResult);
    }
    catch (Exception aEx)
    {
      //If registry disconnected, look up another registry, try again
      lookupRegistry();
      displayQueryResult(aFileName);
    }
  }

  /**
   * Populate the menu list with either registries or remote file services
   * @param aRemoteSet set of RmiId of the remote objects to be display
   * @param aIsRegistry true if the set is registry, else the set is servers
   */
  private void setUpMenuList(ArrayList<RmiId> aRemoteSet, MenuListType aType)
  {
    mMenuListType = aType;
    mMenuItemModel.clear();

    if (aType == MenuListType.eService)
    {
      for (RmiId tRemote : aRemoteSet)
      {
        RemoteObjectListItem tItem =
          new RemoteObjectListItem(
          tRemote.getHost(), tRemote.getName(), "Service", tRemote.getPort());
        mMenuItemModel.addElement(tItem);
      }

      mMenuList.addMouseListener(new MouseAdapter()
      {

        @Override
        public void mouseClicked(MouseEvent aEvent)
        {
          int tIdx = mMenuList.locationToIndex(aEvent.getPoint());
          if (tIdx == -1)
          {
            return;
          }
          Object tTest = mMenuItemModel.get(tIdx);
          if (tTest instanceof RemoteObjectListItem)
          {
            RemoteObjectListItem tItem =
              (RemoteObjectListItem) mMenuItemModel.get(tIdx);
            if (tItem.getClassName().equals("Service"))
            {
              try
              {
                RmiId tId = new RmiId(tItem.getHost(), tItem.getName(), tItem.getPort());
                RemoteFileService tServer = (RemoteFileService) RmiUtils.getRemoteObject(tId);
                List<QueryResult> tFiles = tServer.getFileList();

                /**
                 * If no exception caught here, then assume found a valid server
                 */
                connectToFileService(tId);
              }
              catch (RemoteException aEx)
              {
                JOptionPane.showMessageDialog(null, "Error connect to server. Please try another one");
              }
            }
          }
        }
      });
    }
    else if (aType == MenuListType.eRegistry)
    {
      for (RmiId tRemote : aRemoteSet)
      {
        RemoteObjectListItem tItem =
          new RemoteObjectListItem(
          tRemote.getHost(), tRemote.getName(), "Registry", tRemote.getPort());
        mMenuItemModel.addElement(tItem);
      }
      updateState(ClientDisplayState.eBrowseRegistry);

      mMenuList.addMouseListener(new MouseAdapter()
      {

        @Override
        public void mouseClicked(MouseEvent aEvent)
        {
          int tIdx = mMenuList.locationToIndex(aEvent.getPoint());
          if (tIdx == -1)
          {
            return;
          }

          Object tTest = mMenuItemModel.get(tIdx);
          if (tTest instanceof RemoteObjectListItem)
          {
            RemoteObjectListItem tItem =
              (RemoteObjectListItem) mMenuItemModel.get(tIdx);
            if (tItem.getClassName().equals("Registry"))
            {
              try
              {
                RmiId tId = new RmiId(tItem.getHost(), tItem.getName(), tItem.getPort());
                ServiceRegistry tRegistry = (ServiceRegistry) RmiUtils.getRemoteObject(tId);
                Set<RmiId> tServices = tRegistry.getRegisteredServiceList();
                ArrayList<RmiId> tServiceList = new ArrayList<RmiId>();

                for (RmiId tServiceId : tServices)
                {
                  tServiceList.add(tServiceId);
                }
                setUpMenuList(tServiceList, MenuListType.eService);
                updateState(ClientDisplayState.eBrowseService);
              }
              catch (RemoteException aEx)
              {
                JOptionPane.showMessageDialog(null, "Error connect to server. Please try another one");
              }
            }
          }
        }
      });
    }
  }

  /**
   * Populate the menu list with either registries or remote file services
   * @param aRemoteSet set of RmiId of the remote objects to be display
   * @param aIsRegistry true if the set is registry, else the set is servers
   */
  private void setUpMenuList(List<Transfer> aTranfers, MenuListType aType)
  {
    mMenuListType = aType;
    mMenuItemModel.clear();

    if (aType == MenuListType.eIncompleteFiles)
    {
      for (Transfer tFile : aTranfers)
      {
        FileListItem tItem =
          FileListItem.createIncompleteFile(
          tFile.getId().getFilename(),
          tFile.getFilesize(),
          tFile.getOffset(),
          tFile.getId());
        mMenuItemModel.addElement(tItem);
      }

      mMenuList.addMouseListener(new MouseAdapter()
      {

        @Override
        public void mouseClicked(MouseEvent aEvent)
        {
          int tIdx = mMenuList.locationToIndex(aEvent.getPoint());
          if (tIdx == -1)
          {
            return;
          }

          Object tTest = mMenuItemModel.get(tIdx);
          if (tTest instanceof FileListItem)
          {
            FileListItem tItem =
              (FileListItem) mMenuItemModel.get(tIdx);
            try
            {
              List<Transfer> incomplete = TransferUtils.getIncompleteTransferList(mClientModel.getDatadir());
              for (Transfer transfer : incomplete)
              {
                if (transfer.getId().equals(tItem.getIncompleteTransferId()))
                {
                  DownloadRequest request = new DownloadRequest(mClientId, tItem.getIncompleteTransferId());
                  request.setOffset(transfer.getOffset()); // set the offset
                  mClientModel.download(request);
                  break;
                }
              }
            }
            catch (RemoteException aEx)
            {
              JOptionPane.showMessageDialog(null, "Error connect to server. Please try again");
            }
          }
        }
      });
    }
  }

  /**
   * Connect to a server, and enable the transfer panel
   * @param aFileServiceId
   */
  private void connectToFileService(RmiId aFileServiceId)
  {
    try
    {
      mServer = (RemoteFileService) RmiUtils.getRemoteObject(aFileServiceId);
      mServerId = aFileServiceId;
      updateServerFileList();
      updateState(ClientDisplayState.eTransfer);
    }
    catch (Exception aEx)
    {
      aEx.printStackTrace();
    }
  }

  /**
   * Update the file list of the server currently connected to
   * @param aFileServiceId
   */
  public void updateServerFileList()
  {
    mServerFilesModel.clear();
    try
    {
      List<QueryResult> tFileList = mServer.getFileList();
      for (QueryResult tFile : tFileList)
      {
        if (!tFile.getFilename().endsWith(".incomplete") &&
            !tFile.getFilename().startsWith("."))
        {
          FileListItem tItem =
            FileListItem.createCompleteFile(tFile.getFilename(), (int) tFile.getFilesize());
          mServerFilesModel.addElement(tItem);
        }
      }
    }
    catch (RemoteException aEx)
    {
      if (mCurrentState == ClientDisplayState.eTransfer)
      {
        mTransferProgress.updateIncompleteTransferProgress();
      }
    }
    catch (Exception aEx)
    {
      aEx.printStackTrace();
    }
  }

  /**
   * Update the client file list model
   */
  public void updateClientFileList()
  {
    mClientFilesModel.clear();
    try
    {
      List<FileListItem> tFileList = mClientModel.getLocalFileListItems();
      for (FileListItem tItem : tFileList)
      {
        mClientFilesModel.addElement(tItem);
      }
    }
    catch (Exception aEx)
    {
      aEx.printStackTrace();
    }
  }

  /**
   * Update the menu item label and status label based on the current state
   * @param aState
   */
  private void updateState(ClientDisplayState aState)
  {
    switch (aState.getValue())
    {
      case 0:
        mStatus.setText("Status: Idle. Waiting for command");
        mMenuListLabel.setText("");
        break;
      case 1:
        mStatus.setText("Status: Display Query Result");
        mMenuListLabel.setText("Click on server to connect and start transfer.");
        mServerFilesModel.clear();
        break;
      case 2:
        mStatus.setText("Status: Browsing Registry");
        mMenuListLabel.setText("Click on registry to view servers");
        break;
      case 3:
        mStatus.setText("Status: Browsing Servers");
        mMenuListLabel.setText("Click on server to connect and start transfer.");
        break;
      case 4:
        mStatus.setText("Status: Server is connected. Transfer is enabled");
        break;
      case 5:
        mStatus.setText("Status: Click on an incomplete file to resume");
        mServerFilesModel.clear();
    }
  }

  @Override
  public void download()
  {
    try
    {
      Object tTest = mServerFileList.getSelectedValue();
      if (tTest != null
        && tTest instanceof FileListItem
        && mClientModel != null
        && mServerId != null)
      {
        FileListItem tItem = (FileListItem) tTest;
        TransferId tTransferId =
          new TransferId(
          TransferType.DOWNLOAD,
          mServerId,
          mClientId,
          tItem.getFileName(),
          TransferSource.CLIENT);
        mServer.register(mClientModel);
        DownloadRequest tRequest = new DownloadRequest(mClientId, tTransferId);
        mServer.processRequest(tRequest);
      }
    }
    catch (Exception aEx)
    {
      JOptionPane.showMessageDialog(this, "Server is no longer found. Please query for another server");
      mServerFilesModel.clear();
    }
  }

  @Override
  public void upload()
  {
    try
    {
      Object tTest = mClientFileList.getSelectedValue();
      if (tTest != null
        && tTest instanceof FileListItem
        && mClientModel != null
        && mServerId != null)
      {
        /*
         * The client must register with the service for upload
         */
        mServer.register(mClientModel);
        FileListItem tItem = (FileListItem) tTest;
        TransferId tTransferId =
          new TransferId(
          TransferType.UPLOAD,
          mClientId,
          mServerId,
          tItem.getFileName(),
          TransferSource.SERVICE);
        UploadRequest tRequest = new UploadRequest(mClientId, tTransferId);
        mServer.processRequest(tRequest);
      }
    }
    catch (Exception aEx)
    {
      aEx.printStackTrace();
    }
  }

  @Override
  public void connect()
  {
    //BLAH BLAH
  }

  @Override
  public void query()
  {
    String tFileName =
      JOptionPane.showInputDialog("Please enter the file name to query");
    if (tFileName != null && !tFileName.isEmpty())
    {
      List<QueryResult> results = new ArrayList<QueryResult>();
      try
      {
        results = mClientModel.query(mRegistry.getId(), tFileName);
        ArrayList<RmiId> tResultIds = new ArrayList<RmiId>();
        for (QueryResult tResult : results)
        {
          tResultIds.add(tResult.getId());
        }
        setUpMenuList(tResultIds, MenuListType.eService);
        updateState(ClientDisplayState.eQueryResult);
      }
      catch (RemoteException e)
      {
        lookupRegistry();
        queryAgain(tFileName);
      }
    }
  }

  public void queryAgain(String aFileName)
  {
    List<QueryResult> results = new ArrayList<QueryResult>();
    try
    {
      results = mClientModel.query(mRegistry.getId(), aFileName);
      ArrayList<RmiId> tResultIds = new ArrayList<RmiId>();
      for (QueryResult tResult : results)
      {
        tResultIds.add(tResult.getId());
      }
      setUpMenuList(tResultIds, MenuListType.eService);
      updateState(ClientDisplayState.eQueryResult);
    }
    catch (RemoteException e)
    {
      lookupRegistry();
      queryAgain(aFileName);
    }
  }

  private void updateIncompleteTransferView()
  {
    List<Transfer> tIncompleteList = getIncompleteTransferList();
    setUpMenuList(tIncompleteList, MenuListType.eIncompleteFiles);
    updateState(ClientDisplayState.eIncomplete);
  }

  @Override
  public void resume(Transfer transfer)
  {
    DownloadRequest request = new DownloadRequest(mClientId, transfer.getId());
    request.setOffset(transfer.getOffset());
    try
    {
      mClientModel.download(request);
    }
    catch (RemoteException e)
    {
      JOptionPane.showMessageDialog(this, "Error while trying to resume");
      e.printStackTrace();
    }
  }

  @Override
  public List<Transfer> getIncompleteTransferList()
  {
    List<Transfer> incomplete = new ArrayList<Transfer>();
    try
    {
      incomplete = TransferUtils.getIncompleteTransferList(mClientModel.getDatadir());
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    return incomplete;
  }

  @Override
  public List<File> getLocalFileList()
  {
    return FssUtils.getFileList(mClientModel.getDatadir());
  }

  @Override
  public void clearIncompleteTransferList()
  {
    TransferUtils.removeAllIncompleteTransfers(mClientModel.getDatadir());
  }

  @Override
  public void update(Observable aObservable, Object aObject)
  {
    if (aObject instanceof ClientUIModelEvent)
    {
      ClientUIModelEvent tEvent = (ClientUIModelEvent) aObject;
      switch (tEvent.getType())
      {
        case eDownloadBlockProcessed:
          mTransferProgress.updateTransferProgress(true, tEvent.getTransferProgress());
          break;
        case eUploadBlockProcessed:
          mTransferProgress.updateTransferProgress(false, tEvent.getTransferProgress());
          break;
        case eDownloadCompleted:
          updateClientFileList();
          mTransferProgress.updateTransferProgress(true, 100);
          if (mMenuListType == MenuListType.eIncompleteFiles)
          {
            updateIncompleteTransferView();
          }
          break;
        case eUploadCompleted:
          updateServerFileList();
          mTransferProgress.updateTransferProgress(false, 100);
          break;
        case eLostRegistry:
          lookupRegistry();
          break;
        case eLostService:
          //Nothing for now
          break;
        default:
          break;
      }
    }
  }

  /** This method is called from within the constructor to
   * initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is
   * always regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    mMainMenuPanel = new javax.swing.JPanel();
    mMenuListLabel = new javax.swing.JLabel();
    mMenuListPanel = new javax.swing.JPanel();
    mCommandButtonsPanel = new javax.swing.JPanel();
    mBrowse = new javax.swing.JButton();
    mView = new javax.swing.JButton();
    mQuery = new javax.swing.JButton();
    mClearIncomplete = new javax.swing.JButton();
    mClose = new javax.swing.JButton();
    mTransferPanel = new javax.swing.JPanel();
    mClientFilesLabel = new javax.swing.JLabel();
    mClientFileListPanel = new javax.swing.JScrollPane();
    mClientFileList = new javax.swing.JList();
    mServerFilesLabel = new javax.swing.JLabel();
    mServerFilesListPanel = new javax.swing.JScrollPane();
    mServerFileList = new javax.swing.JList();
    mUpload = new javax.swing.JButton();
    mDownload = new javax.swing.JButton();
    mStatus = new javax.swing.JLabel();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    mMainMenuPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Main Menu"));

    mMenuListLabel.setText("List Description: ");

    mMenuListPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
    mMenuListPanel.setLayout(new java.awt.BorderLayout());

    mBrowse.setText("Browse Registries / Servers");
    mBrowse.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        mBrowseActionPerformed(evt);
      }
    });

    mView.setText("View Incomplete Transfer");
    mView.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        mViewActionPerformed(evt);
      }
    });

    mQuery.setText("Query a File");
    mQuery.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        mQueryActionPerformed(evt);
      }
    });

    mClearIncomplete.setText("Clear Incomplete Transfer");
    mClearIncomplete.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        mClearIncompleteActionPerformed(evt);
      }
    });

    mClose.setText("Close Client");
    mClose.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        mCloseActionPerformed(evt);
      }
    });

    javax.swing.GroupLayout mCommandButtonsPanelLayout = new javax.swing.GroupLayout(mCommandButtonsPanel);
    mCommandButtonsPanel.setLayout(mCommandButtonsPanelLayout);
    mCommandButtonsPanelLayout.setHorizontalGroup(
      mCommandButtonsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addComponent(mQuery, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
      .addComponent(mBrowse, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
      .addComponent(mView, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
      .addComponent(mClearIncomplete, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
      .addComponent(mClose, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
    );
    mCommandButtonsPanelLayout.setVerticalGroup(
      mCommandButtonsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(mCommandButtonsPanelLayout.createSequentialGroup()
        .addComponent(mQuery, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(mBrowse, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(mView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(mClearIncomplete, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(mClose, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );

    javax.swing.GroupLayout mMainMenuPanelLayout = new javax.swing.GroupLayout(mMainMenuPanel);
    mMainMenuPanel.setLayout(mMainMenuPanelLayout);
    mMainMenuPanelLayout.setHorizontalGroup(
      mMainMenuPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mMainMenuPanelLayout.createSequentialGroup()
        .addContainerGap()
        .addComponent(mCommandButtonsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addGroup(mMainMenuPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(mMenuListLabel)
          .addComponent(mMenuListPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 371, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addContainerGap())
    );
    mMainMenuPanelLayout.setVerticalGroup(
      mMainMenuPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(mMainMenuPanelLayout.createSequentialGroup()
        .addContainerGap()
        .addGroup(mMainMenuPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
          .addComponent(mCommandButtonsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
          .addGroup(mMainMenuPanelLayout.createSequentialGroup()
            .addComponent(mMenuListLabel)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(mMenuListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
        .addContainerGap())
    );

    mTransferPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED), "Transfer Panel"));

    mClientFilesLabel.setText("Client Files:");

    mClientFileList.setModel(mClientFilesModel);
    mClientFileList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
    mClientFileListPanel.setViewportView(mClientFileList);

    mServerFilesLabel.setText("Server Files:");

    mServerFileList.setModel(mServerFilesModel);
    mServerFileList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
    mServerFilesListPanel.setViewportView(mServerFileList);

    mUpload.setText(">>");
    mUpload.setToolTipText("Upload");
    mUpload.setEnabled(false);
    mUpload.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        mUploadActionPerformed(evt);
      }
    });

    mDownload.setText("<<");
    mDownload.setToolTipText("Download");
    mDownload.setEnabled(false);
    mDownload.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        mDownloadActionPerformed(evt);
      }
    });

    javax.swing.GroupLayout mTransferPanelLayout = new javax.swing.GroupLayout(mTransferPanel);
    mTransferPanel.setLayout(mTransferPanelLayout);
    mTransferPanelLayout.setHorizontalGroup(
      mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(mTransferPanelLayout.createSequentialGroup()
        .addContainerGap()
        .addGroup(mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(mClientFilesLabel)
          .addComponent(mClientFileListPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 232, javax.swing.GroupLayout.PREFERRED_SIZE))
        .addGap(18, 18, 18)
        .addGroup(mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
          .addComponent(mUpload, javax.swing.GroupLayout.DEFAULT_SIZE, 95, Short.MAX_VALUE)
          .addComponent(mDownload, javax.swing.GroupLayout.DEFAULT_SIZE, 95, Short.MAX_VALUE))
        .addGap(18, 18, 18)
        .addGroup(mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
          .addComponent(mServerFilesLabel, javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(mServerFilesListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE))
        .addContainerGap())
    );
    mTransferPanelLayout.setVerticalGroup(
      mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(mTransferPanelLayout.createSequentialGroup()
        .addGroup(mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addGroup(mTransferPanelLayout.createSequentialGroup()
            .addGap(75, 75, 75)
            .addComponent(mUpload)
            .addGap(18, 18, 18)
            .addComponent(mDownload))
          .addGroup(mTransferPanelLayout.createSequentialGroup()
            .addContainerGap()
            .addGroup(mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
              .addComponent(mClientFilesLabel)
              .addComponent(mServerFilesLabel))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(mTransferPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
              .addComponent(mServerFilesListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 216, Short.MAX_VALUE)
              .addComponent(mClientFileListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 216, Short.MAX_VALUE))))
        .addContainerGap())
    );

    mStatus.setText("Status: ");

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(mTransferPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(mMainMenuPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(mStatus, javax.swing.GroupLayout.DEFAULT_SIZE, 665, Short.MAX_VALUE))
        .addContainerGap())
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(mMainMenuPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addGap(18, 18, 18)
        .addComponent(mTransferPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(mStatus))
    );

    pack();
  }// </editor-fold>//GEN-END:initComponents

    private void mDownloadActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_mDownloadActionPerformed
    {//GEN-HEADEREND:event_mDownloadActionPerformed
      download();
    }//GEN-LAST:event_mDownloadActionPerformed

    private void mQueryActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_mQueryActionPerformed
    {//GEN-HEADEREND:event_mQueryActionPerformed
      query();
    }//GEN-LAST:event_mQueryActionPerformed

    private void mBrowseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_mBrowseActionPerformed
    {//GEN-HEADEREND:event_mBrowseActionPerformed
      ArrayList<RmiId> tRegistries = LookupServiceRegistry.getAvailableRegistryList();
      setUpMenuList(tRegistries, MenuListType.eRegistry);
    }//GEN-LAST:event_mBrowseActionPerformed

    private void mViewActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_mViewActionPerformed
    {//GEN-HEADEREND:event_mViewActionPerformed
      updateIncompleteTransferView();
    }//GEN-LAST:event_mViewActionPerformed

    private void mUploadActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_mUploadActionPerformed
    {//GEN-HEADEREND:event_mUploadActionPerformed
      upload();
    }//GEN-LAST:event_mUploadActionPerformed

    private void mClearIncompleteActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_mClearIncompleteActionPerformed
    {//GEN-HEADEREND:event_mClearIncompleteActionPerformed
      clearIncompleteTransferList();
      if (mMenuListType == MenuListType.eIncompleteFiles)
      {
        mMenuItemModel.clear();
      }
    }//GEN-LAST:event_mClearIncompleteActionPerformed

    private void mCloseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_mCloseActionPerformed
    {//GEN-HEADEREND:event_mCloseActionPerformed
      try
      {
        mRmiRegistry.unbind(mClientId.getName());
      }
      catch (Exception e)
      {
        // ignore
      }
      System.exit(0);
    }//GEN-LAST:event_mCloseActionPerformed

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton mBrowse;
  private javax.swing.JButton mClearIncomplete;
  private javax.swing.JList mClientFileList;
  private javax.swing.JScrollPane mClientFileListPanel;
  private javax.swing.JLabel mClientFilesLabel;
  private javax.swing.JButton mClose;
  private javax.swing.JPanel mCommandButtonsPanel;
  private javax.swing.JButton mDownload;
  private javax.swing.JPanel mMainMenuPanel;
  private javax.swing.JLabel mMenuListLabel;
  private javax.swing.JPanel mMenuListPanel;
  private javax.swing.JButton mQuery;
  private javax.swing.JList mServerFileList;
  private javax.swing.JLabel mServerFilesLabel;
  private javax.swing.JScrollPane mServerFilesListPanel;
  private javax.swing.JLabel mStatus;
  private javax.swing.JPanel mTransferPanel;
  private javax.swing.JButton mUpload;
  private javax.swing.JButton mView;
  // End of variables declaration//GEN-END:variables
}